import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { useControlModel, WithControlPropsType } from '@ant-design/pro-components';
import type { DragEndEvent } from '@dnd-kit/core';
import { closestCenter, DndContext, PointerSensor, useSensor } from '@dnd-kit/core';
import { arrayMove, horizontalListSortingStrategy, SortableContext, useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import type { TabsProps } from 'antd';
import { Button, Flex, Tabs } from 'antd';
import { isArray, toNumber, toString } from 'lodash';
import React, { PropsWithChildren, useMemo, useState } from 'react';

interface DraggableTabPaneProps extends React.HTMLAttributes<HTMLDivElement> {
  'data-node-key': string;
}

const DraggableTabNode: React.FC<Readonly<DraggableTabPaneProps>> = (props) => {
  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
    id: props['data-node-key'],
  });

  const style: React.CSSProperties = {
    ...props.style,
    transform: CSS.Translate.toString(transform),
    transition,
    cursor: 'move',
  };

  return React.cloneElement(props.children as React.ReactElement, {
    ref: setNodeRef,
    style,
    ...attributes,
    ...listeners,
  });
};

const App: React.FC<PropsWithChildren<WithControlPropsType>> = ({ children, ...props }) => {
  const { value = [], onChange } = useControlModel(props);

  const [activeKey, setActiveKey] = useState<string>('0');

  // 递归函数，用于处理嵌套的子元素
  const processChildren = (children: React.ReactNode, index: number): React.ReactNode => {
    return React.Children.map(children, (child) => {
      if (React.isValidElement(child)) {
        // 如果子组件有 name 属性，我们将其扩展
        let name = child.props?.name;

        if (name) {
          if (!Array.isArray(name)) {
            name = [name];
          }
          name = ['pages', index, ...name];
        }

        if (isArray(name) && name.includes('conditions')) {
          return React.cloneElement(child, { ...child.props, ...{ name } });
        }

        // 递归处理子元素的子元素
        const newChildren =
          React.Children.map(child.props.children || [], (child) => processChildren(child, index)) || [];
        // 如果子元素有子元素，我们需要将新的子元素传回去
        if (newChildren.length > 0) {
          return React.cloneElement(child, { ...child.props, ...{ name }, children: newChildren });
        }

        // 如果没有子元素，直接返回克隆后的子元素
        return React.cloneElement(child, { ...child.props, ...{ name } });
      }
      return child;
    });
  };

  const sensor = useSensor(PointerSensor, {
    activationConstraint: { distance: 10 },
  });

  const onDragEnd = ({ active, over }: DragEndEvent) => {
    if (active.id !== over?.id && active.id && over?.id) {
      onChange?.(arrayMove(value, toNumber(active.id), toNumber(over.id)));
      setActiveKey(toString(over.id));
    }
  };

  const handleAdd = () => {
    onChange?.([...value, { name: '页面' }]);
  };
  const handleRemove = (index: number) => {
    onChange?.(value.filter((_: any, i: number) => i !== index));
    setActiveKey('0');
  };

  const items = useMemo<NonNullable<TabsProps['items']>>(() => {
    return value.map((item: any, index: number) => ({
      label: (
        <Flex gap={8}>
          {item.name}
          {value.length > 1 && (
            <MinusCircleOutlined
              style={{ color: 'red' }}
              onClick={(e) => {
                e.stopPropagation();
                handleRemove(index);
              }}
            />
          )}
        </Flex>
      ),
      key: toString(index),
      children: processChildren(children, index),
    }));
  }, [value]);

  return (
    <Tabs
      style={{ width: '100%' }}
      tabBarGutter={10}
      activeKey={activeKey}
      onChange={(activeKey) => setActiveKey(activeKey)}
      items={items}
      centered
      tabPosition="top"
      tabBarExtraContent={{
        right: (
          <Button color="primary" variant="dashed" icon={<PlusCircleOutlined />} onClick={() => handleAdd()}>
            添加页面
          </Button>
        ),
      }}
      renderTabBar={(tabBarProps, DefaultTabBar) => (
        <DndContext sensors={[sensor]} onDragEnd={onDragEnd} collisionDetection={closestCenter}>
          <SortableContext items={items.map((i) => i.key)} strategy={horizontalListSortingStrategy}>
            <DefaultTabBar {...tabBarProps}>
              {(node) => (
                <DraggableTabNode {...node.props} key={node.key}>
                  {node}
                </DraggableTabNode>
              )}
            </DefaultTabBar>
          </SortableContext>
        </DndContext>
      )}
    />
  );
};

export default App;
